﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
using Models.Common;
using Models.Device;
using Models.Task;
using Nancy.TinyIoc;
using Newtonsoft.Json;

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using Utils_ORM;
using Utils_ORM.MySql_IotGateway;
using static Models.Common.EnumDeviceState;
using GateWayCloodService.Data;
using Utils_Cache;
using GateWayCloodService.Device;

namespace GateWayCloodService.CloudCenter
{
    /// <summary>
    /// 场影 条件执行
    /// </summary>
    public class ServiceCloudLinkageCondition
    {
        //  Utils_Redis.UtilRedisHelper utilRedisHelper = new Utils_Redis.UtilRedisHelper();

        //public void taskRun()
        //{
        //    Task.Run(() =>
        //    {
        //        while (true)
        //        {
        //            try
        //            {
        //                //  if (utilRedisHelper.Lock("LinkageCondition_pay"))
        //                //{ //当多节点时，同时只有一处执行
        //                getLinkageConditionTask();
        //                //  utilRedisHelper.DelLock("LinkageCondition_pay");
        //                //  }
        //            }
        //            catch (Exception ex)
        //            {
        //                Console.WriteLine(ex);
        //            }
        //            Thread.Sleep(1000);
        //        }
        //    });
        //}

        /// <summary>
        /// 处理条件任务队列
        /// </summary>
        //public async void getLinkageConditionTask()
        //{
        //    try
        //    {
        //        EFIotGatewayContext ef = new EFIotGatewayContext();
        //        //iot_device_linkage_execute_record first = ef.iot_device_linkage_execute_record.FirstOrDefault();


        //        List<iot_device_linkage_execute_record> lists = ef.iot_device_linkage_execute_record.OrderBy(c => c.ec_id).Take(10).ToList();
        //        foreach (iot_device_linkage_execute_record item in lists)
        //        {
        //            // if (utilRedisHelper.Lock(item.ec_id.ToString(), 3))//避免重复消费
        //            //{
        //            if (item.ec_d_guid != null)
        //            {
        //                Task.Run(() =>
        //                {
        //                    //自动
        //                    linkageConditionAutoRun(item.ec_d_guid, item.ec_execute_type);
        //                });
        //            }
        //            if (item.ec_l_guid != null)
        //            {
        //                Task.Run(() =>
        //                {
        //                    //手动
        //                    linkageHand(item.ec_l_guid, item.ec_execute_type);
        //                });
        //            }
        //            ef.iot_device_linkage_execute_record.Where(c => c.ec_d_guid == item.ec_d_guid).ExecuteDeleteAsync();
        //            ef.SaveChanges();

        //            // new RedisHelper().DelLock(item.ec_id.ToString());
        //            // }
        //        }
        //        //  ef.Dispose();
        //    }
        //    catch (Exception ex)
        //    {
        //        Console.WriteLine(ex.ToString());
        //    }
        //}
        #region
        /// <summary>
        /// 
        /// </summary>
        /// <param name="deviceGuid"></param>
        /// <param name="executeType">0自动运行，1手动运行</param>
        public void linkageConditionAutoRun(string deviceGuid, int executeType)
        {
            try
            {
                EFIotGatewayContext ef = new EFIotGatewayContext();
                List<iot_device_linkage> linkpagelist = (from lk in ef.iot_device_linkage
                                                         join lkc in ef.iot_device_linkage_condition
                                                         on lk.l_guid equals lkc.lc_l_guid
                                                         where lkc.lc_d_guid == deviceGuid && lkc.lc_operation == "main" && lk.l_status == 0 && lkc.lc_status == 0 && lk.l_execute_type == executeType
                                                         select lk).Distinct().ToList();
                foreach (iot_device_linkage item in linkpagelist)
                {
                    linkage(item);
                }
                ef.Dispose();
            }
            catch (Exception ex)
            {
                Console.WriteLine("  LinkageCondition -----error-------" + ex);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="linkageGuid"></param>
        /// <param name="executeType">0自动运行，1手动运行</param>
        //public void linkageHand(string linkageGuid, int executeType)
        //{
        //    try
        //    {
        //        EFIotGatewayContext ef = new EFIotGatewayContext();
        //        iot_device_linkage item = ef.iot_device_linkage.Where(c => c.l_guid == linkageGuid && c.l_execute_type == executeType).FirstOrDefault();

        //        linkage(item);
        //        ef.Dispose();
        //    }
        //    catch (Exception ex)
        //    {
        //        Console.WriteLine("  LinkageCondition -----error-------" + ex);
        //    }
        //}
        /// <summary>
        ///处理条件任务
        /// </summary>
        /// <param name="item"></param>
        public void linkage(iot_device_linkage item)
        {
            EFIotGatewayContext ef = new EFIotGatewayContext();


            //if (utilRedisHelper.Lock(item.l_guid))
            // {
            try
            {
                //  EFIotGatewayContext ef = new EFIotGatewayContext();
                List<iot_device_linkage_condition> operationMainList = ef.iot_device_linkage_condition.Where(c => c.lc_l_guid == item.l_guid && c.lc_operation == "main").ToList();
                //条件判断

                int doBoolTrueCount = 0;//条件成立次数
                int doBoolTotalCount = 0;//总条件数
                foreach (iot_device_linkage_condition itemoperation in operationMainList)
                {
                    doBoolTotalCount = doBoolTotalCount + 1;
                    //条件判断
                    bool itemBool = false;
                    iot_device iot_Device = new ServiceIotDeviceCache().getClientDeviceByCache(itemoperation.lc_d_guid);
                    // iot_device iot_Device = ef.iot_device.Where(c => c.d_guid == itemoperation.lc_d_guid && c.d_status == 0).FirstOrDefault();
                    if (iot_Device == null)
                    {
                        Console.WriteLine(" 条件判断 iot_Device 空");
                        continue;
                    }
                    // iot_device_live_state gwlivestate = ef.iot_device_live_state.Where(c => c.ls_d_guid == iot_Device.d_gw_d_guid && c.ls_live_state_set_time > DateTime.Now.AddMinutes(-2)).FirstOrDefault();
                    iot_device_live_state gwOnLine = new ServiceIotDeviceLiveStateCache().getGateWayIsOnlineByCache(iot_Device.d_gw_d_guid);

                    //判断主机是否在线，在线才执行
                    if (gwOnLine == null)
                    {
                        Console.WriteLine(" 执行内容 iot_Device 主机不在线" + itemoperation.lc_d_guid);
                        continue;
                    }

                    iot_device_model device_Model = new ServiceIotDeviceModelCache().getModelByDeviceCache(itemoperation.lc_d_guid);//.getModelListByCache().Where(c => c.m_guid == iot_Device.d_model_guid).FirstOrDefault();
                    if (device_Model == null)
                    {
                        Console.WriteLine(" 条件判断 iot_Device_Type 空");
                        continue;
                    }

                    itemBool = getValueMatch(itemoperation);
                    if (itemBool)
                    {
                        doBoolTrueCount = doBoolTrueCount + 1;
                    }


                }

                //判断是否or 或and
                if (item.l_condition_type == "or" && doBoolTrueCount > 0)
                {
                    //只有一个条件成立
                    execute_linkageCondition_forDevice(item);
                }
                else if (item.l_condition_type == "and" && doBoolTotalCount > 0 && doBoolTotalCount == doBoolTrueCount)
                {//所有条件成立
                    execute_linkageCondition_forDevice(item);
                }

                // ef.Dispose();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                new ServiceIotSystemLogError().addSystemLogError("linkage 条件处理失败，l_guid:" + item.l_guid, ex.ToString());
            }

            //-------------解锁
            //utilRedisHelper.DelLock(item.l_guid);
            //  }
        }
        public void execute_linkageCondition_forDevice(iot_device_linkage item)
        {
            string groupGuid = item.l_guid;
            try
            {
                EFIotGatewayContext ef = new EFIotGatewayContext();
                List<iot_device_linkage_condition> operationFollowList = ef.iot_device_linkage_condition.Where(c => c.lc_l_guid == item.l_guid && c.lc_operation == "follow" && c.lc_status == 0).OrderBy(c => c.lc_order).ToList();
                //执行内容
                foreach (iot_device_linkage_condition itemfollowoperation in operationFollowList)
                {

                    if (itemfollowoperation.lc_key == "delay")
                    {
                        //延时
                        iot_device_command_processing command_Processing = new iot_device_command_processing();
                        command_Processing.p_d_guid = itemfollowoperation.lc_d_guid;
                        command_Processing.p_guid = Guid.NewGuid().ToString();
                        command_Processing.p_group_guid = groupGuid;//同组
                        command_Processing.p_execute_time = DateTime.Now;
                        command_Processing.p_key = itemfollowoperation.lc_key;
                        command_Processing.p_content = itemfollowoperation.lc_value.ToString();
                        command_Processing.p_execute_time = ((DateTime)command_Processing.p_execute_time).AddSeconds(double.Parse(itemfollowoperation.lc_value));
                        command_Processing.p_repeat_count = 1;
                        new ServiceCloudDeviceCommand().writeDelayedProcessing(command_Processing);
                        continue;
                    }
                    iot_device getDevice = new ServiceIotDeviceCache().getClientDeviceByCache(itemfollowoperation.lc_d_guid);
                    if (getDevice == null)
                    {
                        Console.WriteLine("设备不存在" + itemfollowoperation.lc_d_guid);
                        continue;
                    }
                    iot_device_model iot_Device_Model = new ServiceIotDeviceModelCache().getModelByDeviceCache(itemfollowoperation.lc_d_guid);//.getModelListByCache().Where(c => c.m_guid == getDevice.d_model_guid).FirstOrDefault();
                    if (iot_Device_Model == null)
                    {
                        Console.WriteLine(" 执行内容 iot_device_model 空" + getDevice.d_model_guid);
                        continue;
                    }
                    iot_device_gateway gateway = new ServiceIotDeviceGateWayCache().getGateWayIsOnlineByCache(getDevice.d_gw_d_guid);// ef.iot_device_live_state.Where(c => c.ls_d_guid == getDevice.d_gw_d_guid && c.ls_live_state_set_time > DateTime.Now.AddMinutes(-2)).FirstOrDefault();
                    if (gateway == null)
                    {
                        Console.WriteLine("设备绑定的网关不在线" + getDevice.d_gw_d_guid);
                        continue;
                    }


                    if (iot_Device_Model.m_code == "1001")
                    {  //引脚高低电平控制器

                        //writeSensorlog 注意是否已经写入最新值了，再调用这里，否则可能读取的是旧值，没用
                        //  if (Enum.GetName(typeof(Gpio_Live_State), new ServiceDeviceGpio().getStatus(itemfollowoperation.lc_d_guid)).ToString() != itemfollowoperation.lc_key)
                        //{

                        iot_device_value_current value_Current = new ServiceIotDeviceValueCurrent().getValueCurrentList(itemfollowoperation.lc_d_guid).FirstOrDefault();

                       // if (value_Current.vc_value != itemfollowoperation.lc_key)
                       // { 
                            //查询设备状态状态不是 要执行的状态，就执行
                            new ServiceCloudDeviceCommand().sendCommandToGateWayByGroup(getDevice.d_guid, itemfollowoperation.lc_key, "条件触发器 lc_id:" + itemfollowoperation.lc_id.ToString(), groupGuid);
                           // updateResult(itemfollowoperation);   /// 更新执行状态
                       // }

                        //continue;
                    }
                    else if (iot_Device_Model.m_code == "1018" || iot_Device_Model.m_code == "1019")
                    {
                        iot_device_value_current value_Current = new ServiceIotDeviceValueCurrent().getValueCurrentList(itemfollowoperation.lc_d_guid).FirstOrDefault();
                        //rs485继电器
                        //writeSensorlog 注意是否已经写入最新值了，再调用这里，否则可能读取的是旧值，没用
                        //  if (Enum.GetName(typeof(Gpio_Live_State), new ServiceDeviceGpio().getStatus(itemfollowoperation.lc_d_guid)) != itemfollowoperation.lc_key)
                        // {
                        if (value_Current.vc_value != itemfollowoperation.lc_key)
                        {
                            //查询设备状态状态不是 要执行的状态，就执行
                            new ServiceCloudDeviceCommand().sendCommandToGateWayByGroup(getDevice.d_guid, itemfollowoperation.lc_key, "条件触发器 lc_id:" + itemfollowoperation.lc_id.ToString(), groupGuid);
                           // updateResult(itemfollowoperation);   /// 更新执行状态
                        }
                    }
                    else if (iot_Device_Model.m_code == "1008")
                    {    //lcd显示屏
                        iot_device_display iot_Device_Display = ef.iot_device_display.Where(c => c.dd_d_guid == itemfollowoperation.lc_d_guid).FirstOrDefault();
                        if (iot_Device_Display == null)
                        {
                            Console.WriteLine(" 执行内容 iot_Device_Jidianqi 数据不存在 " + itemfollowoperation.lc_d_guid);
                            continue;
                        }
                        //updateResult(itemfollowoperation);   /// 更新执行状态
                        new ServiceDeviceDisplay().sendCommandToDeviceDisplay1602(new ClientLoginUserInfo(), iot_Device_Display, itemfollowoperation.lc_key);
                    }
                    else
                    {
                        new ServiceCloudDeviceCommand().sendCommandToGateWayByGroup(getDevice.d_guid, itemfollowoperation.lc_key, "条件触发器 lc_id:" + itemfollowoperation.lc_id.ToString(), groupGuid);
                    }


                    updateResult(itemfollowoperation);   /// 更新执行状态
                }

                // ef.Dispose();

            }
            catch (Exception ex)
            {
                Console.WriteLine("  LinkageCondition -----error-------" + ex);
                new ServiceIotSystemLogError().addSystemLogError("execute_linkageCondition_forDevice 条件处理失败，l_guid:" + item.l_guid, ex.ToString());
            }

        }
        #endregion

        /// <summary>
        /// 匹配条件是否已经满足
        /// </summary>
        /// <param name="itemoperation"></param>
        /// <returns></returns>
        protected bool getValueMatch(iot_device_linkage_condition itemoperation)
        {

            EFIotGatewayContext ef = new EFIotGatewayContext();
            //查询当前温度是否到设置值
            iot_device_value_current temperaturesensorItem = ef.iot_device_value_current.Where(c => c.vc_d_guid == itemoperation.lc_d_guid && c.vc_key == itemoperation.lc_key).FirstOrDefault();
            if (temperaturesensorItem == null)
            {
                Console.WriteLine(" 条件判断 temperaturesensorItem 空");
                return false;
            }

            iot_device_model_variable variable= new ServiceIotDeviceVariableCache().getVariableByKey(itemoperation.lc_key);
            if(variable!=null)
            {
                if (variable.v_value_type == "number")
                {
                    if (itemoperation.lc_value_rule == ">")
                    {
                        if (double.Parse(temperaturesensorItem.vc_value) > double.Parse(itemoperation.lc_value))
                        {
                            if (itemoperation.lc_key == "currentFlow")
                            {//埋点
                                new ServiceIotSystemLogError().addSystemLogError(itemoperation.lc_d_guid, "currentFlow：" + temperaturesensorItem.vc_value, "流量计条件触发");
                            }
                            return true;
                        }
                    }
                    else if (itemoperation.lc_value_rule == "=")
                    {
                        if (double.Parse(temperaturesensorItem.vc_value) == double.Parse(itemoperation.lc_value))
                        {
                            return true;
                        }
                    }
                    else if (itemoperation.lc_value_rule == "<")
                    {
                        if (double.Parse(temperaturesensorItem.vc_value) < double.Parse(itemoperation.lc_value))
                        {
                            return true;
                        }
                    }
                }
                else
                {
                    if (temperaturesensorItem.vc_value ==(itemoperation.lc_value))
                    {
                        return true;
                    }
                }
            }
            
            return false;

        }

        /// <summary>
        /// 更新执行状态
        /// </summary>
        /// <param name="iot_Device_Linkage_Condition"></param>
        private void updateResult(iot_device_linkage_condition iot_Device_Linkage_Condition)
        {
            string sql = "update iot_device_linkage set l_execute_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' where l_guid='" + iot_Device_Linkage_Condition.lc_l_guid + "' ";
            new MySqlIotGateway().Db.Ado.ExecuteCommand(sql);
        }
        //EFIotGatewayContext ef = new EFIotGatewayContext();
        /// <summary>
        /// 插入条件执行记录表
        /// </summary>
        /// <param name="dguid"></param>
        /// <param name="executeTime"></param>
        public void insertExecuteRecord(string dguid)
        {

            EFIotGatewayContext ef = new EFIotGatewayContext();
            DateTime dt = DateTime.Now.AddSeconds(-10);
            //if (ef.iot_device_linkage_execute_record.Where(c => c.ec_d_guid == dguid && c.ec_add_time > dt).Count() < 1)
            //{
            if (new UtilRedisHelper().Lock("insertExecuteRecord" + dguid))
            {

                //iot_device_linkage_execute_record iot_Device_Linkage_Execute_Record = new iot_device_linkage_execute_record();
                //iot_Device_Linkage_Execute_Record.ec_d_guid = dguid;
                //iot_Device_Linkage_Execute_Record.ec_execute_type = 0;
                //ef.Add(iot_Device_Linkage_Execute_Record);
                //ef.SaveChanges();
                //ef.Dispose();
                linkageConditionAutoRun(dguid, 0);
                new UtilRedisHelper().DelLock("insertExecuteRecord" + dguid);
            }
            //}

        }

        //public void insertExecuteRecordHandRun(string lguid)
        //{
        //    EFIotGatewayContext ef = new EFIotGatewayContext();
        //    if (ef.iot_device_linkage_execute_record.Where(c => c.ec_d_guid == lguid).Count() > 0)
        //    {
        //        return;
        //    }
        //    iot_device_linkage_execute_record iot_Device_Linkage_Execute_Record = new iot_device_linkage_execute_record();
        //    iot_Device_Linkage_Execute_Record.ec_l_guid = lguid;
        //    iot_Device_Linkage_Execute_Record.ec_execute_type = 1;
        //    ef.iot_device_linkage_execute_record.Add(iot_Device_Linkage_Execute_Record);
        //    ef.SaveChanges();
        //    // ef.Dispose();
        //}
    }
}
